home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
007
/
simplx.arc
/
SIMPLEX.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1985-09-27
|
10KB
|
381 lines
{
This routine performs least squares curve fitting to arbitrary
functions using the simplex method. This algorithm was derived
from an article in the May 1984 issue of BYTE magazine written
by Marco S. Caceci and William P. Cacheris, Florida State Univ.
Refer to that article for an indepth discussion on the mech-
anics of the program. Also see Nelder J.A. and R. Mead,
Computer Jou. 7, 308 (1965) and L.A. Yarbro and S.N. Deming,
Anal. Chim. Acta 74, 391 (1974).
Writen for Turbo Pascal JUNE 1985
by James G. Landowski 72167,2736
Canoga Park, CA.
}
{
Changed 2 to nvpp in several places.
Corrected relative error to allow for negative values
Lew Paper
9/27/85
}
const m = 2; { no. of parameters in equation to fit }
nvpp = 2; { no. of variables per data point to solve for }
n = 3; { points in simplex ( m + 1 ) }
mnp = 200; { max. no. of data points that can be fit }
alfa = 1.0; { reflection coeff. > 0 }
beta = 0.5; { contraction coeff. 0 => 1 }
gamma = 2.0; { expansion coeff. > 1 }
root2 = 1.414214;
type vector = array[1..n] of real;
datavec = array[1..nvpp] of real;
index = 0..255;
var done :boolean;
i,j :index;
hi,lo :array[1..n] of index;
np,
maxiter,
numiter : integer;
next,
center,
mean,
error,
maxerr,
p,q,
step :vector;
simp :array[1..n] of vector;
data :array[1..mnp] of datavec;
fname :string[14];
din,
dout :text;
abs_max :REAL; {L.P.}
{ ----------------------------------------------------------------------}
{ Define the function to be fitted, 'C' is the coeff. vector,
'X' is the independent variable vector. This equation is the
example used in the BYTE article.
}
function fnc(C:vector; X:datavec) :real;
begin
fnc := C[1] * X[1] /( C[2] + X[1] )
end;
{ --------------------------------------------------------------------- }
procedure sumresiduals (var s :vector);
{ computes the sum of squares of the residuals }
var i:index;
begin
s[n] := 0.0;
for i := 1 to np do { do for all data points }
begin
s[n] := s[n] + sqr( fnc(s,data[i])-data[i,nvpp] )
end
end;
{ ----------------------------------------------------------------------- }
procedure inputdata;
{ gets all input data from a disk file. The filename is prompted for
at runtime. An example of input data (from BYTE article) is:
100 maximum no. of iteration in search
.2 3 starting coordinates of simplex
.1 1 starting increments
1e-4 1e-4 1e-4 maximum error
1.68 .172 data ( 'mnp' is max. no. of entries )
3.33 .25 |
5.00 .286 |
6.67 .303 |
10.0 .334 |
20.0 .384 V
}
begin
writeln(dout);
writeln(dout,' Data file used for this run: ',fname);
readln(din,maxiter);
writeln(dout,' Maximum no. of iterations: ',maxiter:5);
writeln(dout);
writeln(dout,' Starting coordinates: ');
write(dout,' ');
for i := 1 to m do
begin
read(din,simp[1,i]);
write(dout,simp[1,i],' ');
end;
writeln(dout);
readln(din);
writeln(dout);
writeln(dout,' Starting steps:');
write(dout,' ');
for i := 1 to m do
begin
read(din,step[i]);
write(dout,step[i],' ');
end;
writeln(dout);
readln(din);
writeln(dout);
writeln(dout,' Maximum errors:');
write(dout,' ');
for i := 1 to n do
begin
read(din,maxerr[i]);
write(dout,maxerr[i],' ');
end;
writeln(dout);
readln(din);
writeln(dout);
writeln(dout,' Data:');
np := 0;
while NOT EOF(din) do
begin
np :=succ(np);
write(dout,' #',np:2);
for j := 1 to nvpp do
begin
read(din,data[np,j]);
write(dout,data[np,j])
end;
readln(din);
writeln(dout);
end
end;
{ ----------------------------------------------------------------------- }
procedure outputdata;
var y, dy, sigma :real;
{ pltout :text;}
begin
{ Open output files for plot data when needed. }
{ assign(pltout,'SIMPLEX.PLT'); }
{ rewrite(pltout); }
writeln(dout);
writeln(dout,' Completion after ',numiter:5,' iterations');
writeln(dout);
writeln(dout,' Final Simplex:');
for j := 1 to n do
begin
write(dout,' ');
for i := 1 to n do
write(dout,simp[j,i]:12,' ');
writeln(dout);
end;
writeln(dout);
writeln(dout,' Mean(s): ');
for i := 1 to n do
begin
if i <> n then writeln(dout,' C',i:1,' ',mean[i]);
if i = n then writeln(dout,' Residual: ',mean[i]);
end;
writeln(dout);
writeln(dout,' Fractional Error:');
write(dout,' ');
for i := 1 to n do
write(dout,error[i]);
writeln(dout);
writeln(dout);
sigma := 0.0;
for i := 1 to np do
begin
y := fnc(mean,data[i]);
dy := data[i,nvpp]-y;
sigma := sigma+sqr(dy);
end;
sigma := sqrt(sigma/np);
writeln(dout,' Std. Dev. of error: ',sigma);
sigma := sigma/sqrt(np-m);
writeln(dout,' Estimate of error : ',sigma);
writeln(dout);
writeln(dout,' # x y y" dy');
for i := 1 to np do
begin
y := fnc(mean,data[i]);
dy := data[i,nvpp]-y;
writeln(dout ,i:3,' ',data[i,1]:12,' ',data[i,nvpp]:12,' ',y:12,' ',
dy:12);
{ writeln(pltout,i:3,' ',data[i,1]:12,' ',data[i,nvpp]:12,' ',y:12,' ',
dy:12); }
end;
writeln(dout);
writeln(dout,' -Done- ');
end;
{ ----------------------------------------------------------------------- }
procedure first;
begin
writeln(dout);
writeln(dout,' Starting SIMPLEX');
writeln(dout);
for j := 1 to n do
begin
write(dout,' simp[',j:1,'] ');
for i := 1 to n do
write(dout,simp[j,i]:12,' ');
writeln(dout)
end;
writeln(dout);
end;
{ ----------------------------------------------------------------------- }
procedure newvertex;
begin
{ write(dout,' -> ',numiter:4); }
for i := 1 to n do
begin
simp[hi[n],i] := next[i];
{ write(dout,next[i]) }
end;
{ writeln(dout) }
end;
{ ----------------------------------------------------------------------- }
procedure order;
var i,j :integer;
begin
for j := 1 to n do
begin
for i := 1 to n do
begin
if simp[i,j] < simp[lo[j],j] then lo[j] :=i;
if simp[i,j] > simp[hi[j],j] then hi[j] :=i;
end
end
end;
{ ----------------------------------------------------------------------- }
{ Main }
begin
write('Filename: ');
readln(fname);
assign(din,fname);
reset(din);
assign(dout,'simplex.out');
rewrite(dout);
inputdata;
sumresiduals(simp[1]);
for i := 1 to m do
begin
p[i] := step[i]*(sqrt(n)+m-1)/(m*root2);
q[i] := step[i]*(sqrt(n)-1)/(m*root2)
end;
for i := 2 to n do
begin
for j := 1 to m do simp[i,j] := simp[1,j] + q[j];
simp[i,i-1] := simp[1,i-1]+p[i-1];
sumresiduals(simp[i])
end;
for i := 1 to n do
begin
lo[i] := 1;
hi[i] := 1
end;
order;
first;
numiter := 0;
repeat
done := true;
numiter := succ(numiter);
for i := 1 to n do
center[i] := 0.0;
for i := 1 to n do
if i<>hi[n] then
for j := 1 to m do
center[j] := center[j]+simp[i,j];
for i := 1 to n do
begin
center[i] := center[i]/m;
next[i] := (1.0+alfa)*center[i]-alfa*simp[hi[n],i];
end;
sumresiduals(next);
if next[n] <= simp[lo[n],n] then
begin
newvertex;
for i := 1 to m do
next[i] := gamma*simp[hi[n],i]+(1.0-gamma)*center[i];
sumresiduals(next);
if next[n] <= simp[lo[n],n] then newvertex;
end
else
begin
if next[n] <= simp[hi[n],n] then
newvertex
else
begin
for i := 1 to m do
next[i] := beta*simp[hi[n],i]+(1.0-beta)*center[i];
sumresiduals(next);
if next[n] <= simp[hi[n],n] then
newvertex
else
begin
for i := 1 to n do
begin
for j := 1 to m do
simp[i,j] := (simp[i,j]+simp[lo[n],j])*beta;
sumresiduals(simp[i]);
end
end
end
end;
order;
for j := 1 to n do
begin
IF ABS(simp[hi[j], j]) > ABS(simp[lo[j], j]) {L.P.}
THEN {L.P.}
abs_max := ABS(simp[hi[j], j]) {L.P.}
ELSE {L.P.}
abs_max := ABS(simp[lo[j], j]); {L.P.}
error[j] :=
(simp[hi[j],j]-simp[lo[j],j])/abs_max; {L.P.}
if done then
if error[j] > maxerr[j] then done := false;
end;
until (done or (numiter = maxiter));
for i := 1 to n do
begin
mean[i] := 0.0;
for j := 1 to n do
mean[i] := mean[i]+simp[j,i];
mean[i] := mean[i]/n;
end;
outputdata;
close(dout);
{ close(pltout); }
writeln;
writeln('Done.... results in file "SIMPLEX.OUT"');
end.
$